/*
  Copyright (C) 2011, Kyungjoo Kim
  
  This file is part of LINAL (LINear ALgebra)
  
  All rights reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.
  
  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.
  
  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  Also add information on how to contact you by electronic and paper mail.
  
  
  Kyungjoo Kim
  iamkyungjoo@gmail.com
*/
#ifndef LINAL_OPERATION_MACRO_HXX
#define LINAL_OPERATION_MACRO_HXX

/*! Control tree for the FLAME internal functions
*/ 

extern fla_qrutinc_t* flash_qrutinc_cntl;

extern fla_qrut_t   * fla_qrut_cntl_leaf;
extern fla_apqut_t  * fla_apqut_cntl_leaf;

extern fla_qr2ut_t  * fla_qr2ut_cntl_leaf;
extern fla_apq2ut_t * fla_apq2ut_cntl_leaf;

extern fla_axpy_t   * flash_axpy_cntl_blas;
extern fla_copy_t   * flash_copy_cntl_blas;
extern fla_scal_t   * flash_scal_cntl_blas;
extern fla_appiv_t  * flash_appiv_cntl;

extern fla_chol_t   * flash_chol_cntl_leaf;
extern fla_lu_t     * flash_lu_nopiv_cntl_leaf;
extern fla_lu_t     * flash_lu_piv_cntl_leaf;

extern fla_qrut_t   * flash_qrut_cntl_leaf;
extern fla_apqut_t  * flash_apqut_cntl_leaf;

extern fla_qr2ut_t  * flash_qr2ut_cntl_leaf;
extern fla_apq2ut_t * flash_apq2ut_cntl_leaf;

extern fla_trsm_t   * flash_trsm_cntl_blas;
extern fla_gemm_t   * flash_gemm_cntl_blas;
extern fla_trmm_t   * flash_trmm_cntl_blas;

extern fla_lu_t     * flash_lu_nopiv_cntl;
extern fla_trsm_t   * flash_trsm_cntl_mm;
extern fla_gemm_t   * flash_gemm_cntl_mm_op;
extern fla_trmm_t   * flash_trmm_cntl_mm;

/*!  Macro
 */
#define LINAL_TR_LEFT(quad, side)		\
  {						\
    FLA_Part_2x2( ~A, &ATL, &ATR,		\
	              &ABL, &ABR, 0, 0, quad );	\
    FLA_Part_2x1( ~B, &BT,			\
		      &BB, 0, side);		\
  }

#define LINAL_TR_RIGHT(quad, side)		\
  {						\
    FLA_Part_2x2( ~A, &ATL, &ATR,		\
		      &ABL, &ABR, 0, 0, quad );	\
    FLA_Part_1x2( ~B, &BL, &BR, 0, side);	\
  }

#define LINAL_TR_LEFT_LOOP_HEAD(quad, side)			\
  {								\
    FLA_Repart_2x2_to_3x3( ATL, ATR,     &A00, &A01, &A02,	\
			   &A10, &A11, &A12,			\
                           ABL, ABR,     &A20, &A21, &A22,	\
                           1, 1, quad );			\
    FLA_Repart_2x1_to_3x1( BT,           &B0,			\
			   &B1,					\
                           BB,           &B2,			\
                           1, side);				\
  }

#define LINAL_TR_LEFT_LOOP_TAIL(quad, side)			\
  {                                                             \
    FLA_Cont_with_3x3_to_2x2( &ATL,  &ATR,  A00, A01, A02,      \
			                    A10, A11, A12,	\
                              &ABL, &ABR,   A20, A21, A22,      \
                              quad );                           \
    FLA_Cont_with_3x1_to_2x1( &BT,          B0,                 \
			                    B1,			\
                              &BB,          B2,                 \
                              side);                            \
  }

#define LINAL_TR_RIGHT_LOOP_HEAD(quad, side)			\
  {								\
    FLA_Repart_2x2_to_3x3( ATL, ATR,     &A00, &A01, &A02,	\
			                 &A10, &A11, &A12,	\
                           ABL, ABR,     &A20, &A21, &A22,	\
                           1, 1, quad );			\
    FLA_Repart_1x2_to_1x3( BL, BR,       &B0, &B1, &B2,		\
                           1, side);				\
  }

#define LINAL_TR_RIGHT_LOOP_TAIL(quad, side)			\
  {                                                             \
    FLA_Cont_with_3x3_to_2x2( &ATL,  &ATR,  A00, A01, A02,      \
			                    A10, A11, A12,	\
                              &ABL, &ABR,   A20, A21, A22,      \
                              quad );                           \
    FLA_Cont_with_1x3_to_1x2( &BL, &BR,     B0, B1, B2,         \
                              side );                           \
  }

#define LINAL_CHOL_U_TRSM(A11, A12)                                     \
  {                                                                     \
    trsm( FLA_LEFT, FLA_UPPER_TRIANGULAR, FLA_CONJ_TRANSPOSE,           \
          FLA_NONUNIT_DIAG, FLA_ONE, A11, A12 );                        \
  }
#define LINAL_CHOL_U_HERK(A12, A22)                                     \
  {                                                                     \
    herk( FLA_UPPER_TRIANGULAR, FLA_CONJ_TRANSPOSE, FLA_MINUS_ONE,      \
          A12, FLA_ONE, A22 );                                          \
  }
#define LINAL_CHOL_L_TRSM(A11, A21)                                     \
  {                                                                     \
    trsm( FLA_RIGHT, FLA_LOWER_TRIANGULAR, FLA_CONJ_TRANSPOSE,          \
          FLA_NONUNIT_DIAG, FLA_ONE, A11, A21 );                        \
  }
#define LINAL_CHOL_L_HERK(A21, A22)                                     \
  {                                                                     \
    herk( FLA_LOWER_TRIANGULAR, FLA_NO_TRANSPOSE, FLA_MINUS_ONE,   \
          A21, FLA_ONE, A22 );                                          \
  }
#define LINAL_LDL_L_TRSM(A11, A21)                              \
  {                                                             \
    trsm( FLA_RIGHT, FLA_UPPER_TRIANGULAR, FLA_NO_TRANSPOSE,    \
          FLA_NONUNIT_DIAG, FLA_ONE, A11, A21 );                \
  }
#define LINAL_LDL_L_GEMM(A21, A12, A22)                         \
  {                                                             \
    gemm_l( FLA_NO_TRANSPOSE, FLA_NO_TRANSPOSE, FLA_MINUS_ONE,  \
            A21, A12, FLA_ONE, A22 );                           \
  }
#define LINAL_LU_TRSM_A12(A11, A12)                             \
  {                                                             \
    trsm( FLA_LEFT, FLA_LOWER_TRIANGULAR, FLA_NO_TRANSPOSE,     \
          FLA_UNIT_DIAG, FLA_ONE, A11, A12 );                   \
  }
#define LINAL_LU_TRSM_A21(A11, A21)                             \
  {                                                             \
    trsm( FLA_RIGHT, FLA_UPPER_TRIANGULAR, FLA_NO_TRANSPOSE,    \
          FLA_NONUNIT_DIAG, FLA_ONE, A11, A21 );                \
  }
#define LINAL_LU_GEMM(A21, A12, A22)                            \
  {                                                             \
    gemm( FLA_NO_TRANSPOSE, FLA_NO_TRANSPOSE, FLA_MINUS_ONE,    \
          A21, A12, FLA_ONE, A22 );                             \
  }

#endif
